//---------------------------------------------------------------------------
#pragma hdrstop

#include "DoComp.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
}



//----------------------------//
//                            //
//----------------------------//
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  cpu.ram = (BYTE *)malloc( 0x20000 );
  if ( !cpu.ram ){
    ShowMessage("Fatal Error: Could not allocate memory!" );
    Close( );
    return;
  }
  //
  memset( cpu.ram, 0, 0x20000 );
}


//----------------------------//
//                            //
//----------------------------//
void __fastcall TForm1::OpenROMfile1Click(TObject *Sender)
{
  char buf[1024];

  Open1->Title = "Open ROM File...";
  //---------------------//
  //                     //
  //---------------------//
  if ( Open1->Execute( ) )
  { //
    strcpy( romf, Open1->FileName.c_str( ) );
    rf = fopen( romf, "rb" );
    if ( !rf ){
      ShowMessage("Fatal Error: Could not open file!");
      return;
    }
    //
    _free( cpu.rom );
    cpu.rom = (BYTE *)malloc( cpu.FSize = FileSize( rf ) );
    //
    if ( !cpu.rom ){
      fclose( rf );
      ShowMessage( "Fatal Error: Could not allocate needed memory!" );
      Close( );
    }

    // Check for dumb header
    if ( cpu.FSize & 0x0200 ) {
      cpu.FSize -= 0x0200;
      fseek( rf, 0x0200, SEEK_SET );
    }
    // Read in the data
    fread( cpu.rom, 1, cpu.FSize, rf );
    // Test to make sure i's THE ROM
    if ( FileSize( rf ) < 0x1747A || strncmp( &cpu.rom[0x1747A], "Light Fantasy 2 95/08/10", 24 ) ){
      ShowMessage("Error: Not the correct ROM File..." );
      _free( cpu.rom );
      fclose( rf );
      return;
    }
    fclose( rf );
    //
    ShowMessage("ROM File was loaded successfully!" );
    //
    Open1->FileName = ExtractFileDir( Open1->FileName );
    strcpy( dirc, Open1->FileName.c_str( ) );
    //
    sprintf( buf, "%s\\Comp", dirc );
    mkdir( buf );
  }
}


//----------------------------//
//                            //
//----------------------------//
void __fastcall TForm1::Exit1Click(TObject *Sender)
{
  Close( );
}


//----------------------------//
//                            //
//----------------------------//
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  _free( cpu.rom );
  _free( cpu.ram );
}


//-------------------------------//
//                               //
//-------------------------------//
void __fastcall TForm1::Decompress8x8Font1Click(TObject *Sender)
{
  FILE *sf;
  int  data;
  char scf[MAXPATH << 1];

  if ( !cpu.rom ){
    ShowMessage("Error: Must load a ROM file." );
    return;
  }

  sprintf( scf, "%s\\Comp\\8x8font.doc", dirc );
  sf = fopen( scf, "wt" );
  if ( !sf ){
    ShowMessage("Error: Could not create the scripting dump file." );
    return;
  }

  sprintf( txtf, "%s\\Comp\\8x8.cmp", dirc );
  data = Decompress( Snes2Pc(0x89DB95), txtf, sf );
  switch( data )
  { //
    case 0 : break;
    case 1 : ShowMessage("Error: Data not supported in decompressor."); return;
    case 2 : ShowMessage("Fatal Error: Could not open Dump file."); return;
    case 3 : ShowMessage("Error: Please load a ROM first." ); return;
    default: ShowMessage("Unknown Error..."); return;
  }

  fclose( sf );
  //
  ShowMessage("Font file has been decompressed\n");
}



//---------------------------------//
//                                 //
//---------------------------------//
void __fastcall TForm1::Block11Click(TObject *Sender)
{
  LONG offsets[0x1000];
  int  c,
       same_pos;
  FILE *sf;
  int  data;
  TMenuItem *m = (TMenuItem *)Sender;
  //
  char scf[MAXPATH << 1];

  if ( !m->Tag ) return;
  if ( !cpu.rom ){
    ShowMessage("Error: Please load a ROM first." );
    return;
  }
  //
  memset( offsets, 0, 0x1000 * 4 );
  cpu.offs  = Snes2Pc( m->Tag );
  reg.stack = WGET( cpu.rom, cpu.offs );
  //
  reg.stack = (reg.stack - (m->Tag & 0xFFFF)) / (3 - m->GroupIndex); 
  // Get a script file
  sprintf( scf, "%s\\Comp\\%08X.doc", dirc, m->Tag );
  sf = fopen( scf, "wt" );
  if ( !sf ){
    ShowMessage("Error: Could not create the scripting dump file." );
    return;
  }

  //------------------//
  // Decompress shit! //
  //------------------//
  reg.x = -1;
  same_pos = 0;
  while( ++reg.x < reg.stack )
  { //
    _ReLoop:
    if ( m->GroupIndex )
      cpu.posi = (LGET( cpu.rom, (cpu.offs + (reg.x << 1)) ) & 0x0000FFFF) | (m->Tag & 0xFF0000);
    else
      cpu.posi = LGET( cpu.rom, (cpu.offs + (reg.x * 3)) ) & 0x0FFFFFF;
    //
    for ( c = 0; c < same_pos; c++ ){
      if ( cpu.posi == offsets[ c ] ){
        reg.x++;
        goto _ReLoop;
      }
    }
    //
    offsets[ same_pos++ ] = cpu.posi;
    sprintf( txtf, "%s\\Comp\\%08X.%03d", dirc, m->Tag, reg.x );
    //
    data = Decompress( Snes2Pc(cpu.posi), txtf, sf );
    switch( data )
    { //
      case 0 : break;
      case 1 : break;// ShowMessage("Error: Data not supported in decompressor."); break;
      case 2 : ShowMessage("Fatal Error: Could not open Dump file\n\"" + AnsiString( txtf ) + "\"."); return;
      case 3 : ShowMessage("Error: Please load a ROM first." ); return;
      default: ShowMessage("Unknown Error..."); return;
    }
  }// WEND

  fclose( sf );
  ShowMessage("All Files Dumped!");
}



//-----------------------------------//
//                                   //
//-----------------------------------//
void __fastcall TForm1::Recompressafile1Click(TObject *Sender)
{
  FILE *sf;
  int  data;

  if ( !romf[0] ){
    ShowMessage( "Error: Must load ROM file first.");
    return;
  }

  Open1->Title = "Open Format Text File...";
  Open1->FileName = "";
  if ( Open1->Execute( ) )
  { //
    strcpy( txtf, Open1->FileName.c_str( ) );
    //
    sf = fopen( txtf, "rt" );
    if ( !sf ){
      ShowMessage("Error: Could not open Format File..." );
      return;
    }

    data = 0;
    // Clear Error log
    ListBox1->Clear( );

    while( LoadTagData( sf ) != -1 && data < 2 ){
      data = Recompress( Start, End, txtf, romf );
//      ShowMessage("Data file \"%s\" Recompressed!\n", txtf);
    }

    // Kill the instance of ROM in
    // case we try to DECOMPRESS!
    _free( cpu.rom );
  }
}


//---------------------------------//
//                                 //
//---------------------------------//
int  __fastcall TForm1::Decompress( LONG lpOffset, char *OutputFile, FILE *sf )
{
  BYTE data;

  if ( cpu.rom )
  { //------------------//
    // Decompress shit! //
    //------------------//
    cpu.posi = lpOffset;
    data     = cpu.rom[ cpu.posi + 3 ];
    //---------------//
    // Standard data //
    //---------------//
    if ( !data )
    { // Dump data to script file
      fprintf( sf, ".COMP  %s  %s  %08X", romf, OutputFile, cpu.posi );
      //
      WRAM( 0x1305 ) = WGET( cpu.rom, cpu.posi );
      WRAM( 0x1301 ) = 0x03EE;
      WRAM( 0x12FF ) = 0x0000;
      reg.y = 4;
      //
      while( WRAM(0x1305)  > 0 )
      { //
        cpu.ram[0x1303] = cpu.rom[ cpu.posi + reg.y ];
        reg.y++;
        cpu.ram[0x1304] = 0x08;
        //
        while( cpu.ram[0x1304]-- )
        { //------------------//
          // Regular data     //
          //------------------//
          if ( cpu.ram[0x1303 ] & 0x01 )
          { // Store ROM data, non-cmpressed
            data = cpu.rom[ cpu.posi + reg.y ];
            reg.y++;
            //
            cpu.ram[ 0x2000 + WRAM(0x12FF) ] = data;
            WRAM( 0x12FF ) += 1;
            WRAM( 0x130D ) += 1;
            //
            cpu.ram[ 0x01F800 + WRAM(0x1301) ] = data;
            WRAM(0x1305) -= 1;
            WRAM(0x1301) += 1;
            WRAM(0x1301) &= 0x03FF;
          }
          else
          //------------------//
          // Decompress       //
          //------------------//
          { // Decompress data
            WRAM(0x130D) += 2;
            cpu.ram[0x130B]   = cpu.rom[ cpu.posi + reg.y ];
            reg.y++;
            cpu.ram[0x130C]   = 0;
            //
            cpu.ram[0x130F]   = cpu.rom[ cpu.posi + reg.y ];
            reg.y++;
            cpu.ram[0x1310]   = 0;
            //
            reg.a = (cpu.ram[0x130F] & 0xF0) << 4;
            WRAM(0x130B) += reg.a;
            //
            cpu.ram[0x130F]  = (cpu.ram[0x130F] & 0x0F) + 3;
            // Copy th4e data
            while(  cpu.ram[0x130F]-- > 0 )
            { //
              cpu.ram[ 0x002000 + WRAM(0x12FF) ] = cpu.ram[ 0x01F800 + WRAM(0x130B) ];
              cpu.ram[ 0x01F800 + WRAM(0x1301) ] = cpu.ram[ 0x01F800 + WRAM(0x130B) ];
              //
              WRAM(0x12FF) += 1;
              WRAM(0x130B) += 1;
              WRAM(0x130B) &= 0x03FF;
              //
              WRAM(0x1301) += 1;
              WRAM(0x1301) &= 0x03FF;

              WRAM(0x1305) -= 1;
              if ( WRAM(0x1305) == 0 ) break;
            }// WEND - $130F

          }// END IF - BIT Test

          cpu.ram[0x1303] >>= 1;
          // Test end of compression
          if ( WRAM(0x1305) == 0 ) break;
        }// WEND - 8 loops

      }// END - $1305
    }
    else
    //----------------------//
    // Who knows            //
    //----------------------//
    if ( data == 0x01 )
    { //
      reg.y = 0;
      return 1;
    }
    else
    //----------------------//
    // Tile map data, maybe?//
    //----------------------//
    if ( data == 0x02 )
    { //
      reg.y = 0;
      return 1;
    }
    else
    //----------------------//
    // Direct data store    //
    //----------------------//
    {
      WRAM( 0x1305 )  = WGET( cpu.rom, cpu.posi );
      WRAM( 0x1305 ) += 2;
      WRAM( 0x12FF )  = WRAM( 0x1305 );
      reg.y = 4;
      reg.a = 0x2000;
      //
      while( WRAM(0x1305) > 0 )
      { //
        cpu.ram[ reg.a ] = cpu.rom[ cpu.posi + reg.y ];
        reg.a++;
        reg.y++;
        WRAM(0x1305) -= 1;        
      }
    }

    // Open file and dump to it!
    df = fopen( OutputFile, "wb" );
    if ( !df ){
      fcloseall( );
      Close( );
      return 2;
    }
    //
    fwrite( &cpu.ram[0x2000], 1, WRAM(0x12FF), df );
    fclose( df );

    // Dump data to script file
    fprintf( sf, "  %08X\n", cpu.posi + reg.y );

  }
  else
  { // No ROM loaded
    return 3;
  }

  return 0;
}


//---------------------------------//
//                                 //
//---------------------------------//
int  __fastcall TForm1::Recompress( LONG ofStart, LONG ofEnd, char *InputFile, char *OutputFile )
{
  char tuf[512];
  BYTE buf[0x400];
  LONG Lof;
  WORD bfPosi;

	df = fopen( InputFile, "rb" );
  if ( !df ){
    ShowMessage("Fatal Error: Could not open Input file." );
    return 2;
  }
	Lof     = FileSize( df );

  //
  cpu.rom = (BYTE *)malloc( 0x10000 );
  if ( !cpu.rom ){
    ShowMessage("Fatal Error: Could not allocate needed memory." );
    return 2;
  }

  // Read data to be compressed
	fread( cpu.ram, 1, Lof, df );
	fclose( df );
  memset( cpu.rom, 0, 0x10000 );
  memset( buf    , 0, 0x00400 );

  cpu.lpCPos    =
  cpu.lpRPos    = 0;
  cmp.posi      =
  cmp.back_posi = 0;

  cmp.bit_pos   = 0;
  cmp.count     = 0;
  cmp.posi      = 0;
  bfPosi        = 0x03EE;

  //-------------------------------------//
  // Start of Main Recompression Routine //
  //-------------------------------------//
	while( cmp.posi < Lof )
  { // Loop for 8 BITS
    reg.y = 8;
    cmp.bit_pos = 0;

    while( reg.y-- > 0 )
    { //
//*/
      if ( cmp.posi > 0x03FF )
        cmp.back_posi = ( cmp.posi - 0x03FF );
      else
        cmp.back_posi = 0;
/*/
      cmp.back_posi = 0x3EE;
/**/
      //------------------------------//
      // Search for compressable data //
      //------------------------------//
      cmp.most  = 0;
      //
      while( cmp.back_posi < cmp.posi )
//      while( cmp.back_posi < 0x13EE )
      { //
        if ( cpu.ram[ cmp.posi ] == cpu.ram[ cmp.back_posi ] )
//        if ( cpu.ram[ cmp.posi ] == buf[ (cmp.back_posi & 0x3FF) ] )
        { //
          cmp.count = 0;

          // Loop while new data matches old data
//*/
          while( ( cpu.ram[ cmp.posi + cmp.count ] == cpu.ram[ cmp.back_posi + cmp.count ] ) &&
                 ( cmp.posi + cmp.count ) < Lof && cmp.count < 18
               )
/*/
          while( ( cpu.ram[ cmp.posi + cmp.count ] == buf[ (cmp.back_posi + cmp.count) & 0x3FF ] ) &&
                 ( cmp.posi + cmp.count ) < Lof && cmp.count < 18
               )
/**/
            cmp.count++;

          // If more data found, change most
          if ( cmp.count > cmp.most ) {
//*/
           cmp.most_posi = ( ( cmp.back_posi - 0x12 ) & 0x03FF );
/*/
            cmp.most_posi = ( cmp.back_posi & 0x03FF );
/**/
            cmp.most      = cmp.count;
          }// END IF

          // Break if the maxium amount of data is reached
          if ( cmp.most >= 18 ){
            cmp.most = 18;
            break;
          }
        }// END IF
        //
        cmp.back_posi++;
      }// WEND - bck < cpos

      // Make sure we don'thave a better pattern up next
/*
      if ( cmp.most > 2 ){
        int k = MakeSure( buf, reg, cpu, cmp, bfPosi, Lof )-1;
        if ( k > cmp.most )
          cmp.most = 1;
      }
*/
      //------------------------------//
      // Test for Regular or Compress //
      // data storage                 //
      //------------------------------//
      if ( cmp.most >= 3 )
      { //
        reg.a  = ( cmp.most - 3 ) & 0x000F;
        reg.a |= ( cmp.most_posi >> 4 ) & 0x00F0;
        reg.a |= ( cmp.most_posi & 0x00FF ) << 8;
        //
        cmp.buffer[ cpu.lpCPos++ ] = (reg.a >> 8) & 0xFF;
        cmp.buffer[ cpu.lpCPos++ ] = (reg.a & 0xFF);
        cmp.bit_pos >>= 1;
        // Copy data to temp buffer
/*/
        while( cmp.most-- ){
          buf[ bfPosi++ ] = cpu.ram[ cmp.posi++ ];
          bfPosi &= 0x3FF;
        }
        //
/*/
        cmp.posi     += cmp.most;
/**/
      }
      else
      { // store the regular data
//        buf[ bfPosi++ ] = cpu.ram[ cmp.posi ];
        bfPosi &= 0x3FF;
        cmp.buffer[ cpu.lpCPos++ ] = cpu.ram[ cmp.posi++ ];
        cmp.bit_pos >>= 1;
        cmp.bit_pos  |= 0x80;
      }// END IF
    }// WEND - 8-BIT Loop

    // Transfer the data
    cpu.rom[ cpu.lpRPos++ ] = cmp.bit_pos;
    memcpy( &cpu.rom[ cpu.lpRPos ], cmp.buffer, cpu.lpCPos );
    cpu.lpRPos += cpu.lpCPos;
    // Reset data
    cmp.bit_pos = 0;
    cpu.lpCPos  = 0;
    memset( cmp.buffer, 0, 18 );
  } // WEND - Lof

  //-----------------------------------//
  // Try to recompress back to the ROM //
  //-----------------------------------//
  if ( cpu.lpRPos <= (ofEnd - (ofStart+4)) )
  { //
    rf = fopen( OutputFile, "r+b" );
    if ( !rf ){
      ShowMessage("Fatal Error: Could not open Output File." );
      return 2;
    }
    //
    fseek( rf, ofStart, SEEK_SET );
    // File size
    fwrite( &cmp.posi, 1, 2, rf );

    // Store the Data
    fseek( rf, ofStart + 4, SEEK_SET );
    fwrite( cpu.rom, 1, cpu.lpRPos, rf );
    fclose( rf );
    //
    sprintf( tuf,
            "Compresed \"%s\" successfully with %d BYTES to spare!",
            InputFile,
            (ofEnd - (ofStart+4)) - cpu.lpRPos
           );
//    ShowMessage( tuf );
    ListBox1->Items->Add( AnsiString( tuf ) );
  }
  else
  {
    sprintf( tuf,
            "Error: Data %d BYTES too large to save from file: \"%s\"!",
            cpu.lpRPos - (ofEnd - (ofStart+4)),
            InputFile
           );
//    ShowMessage( tuf );
    ListBox1->Items->Add( AnsiString( tuf ) );
    return 1;
  }

  return 0;
}// End Of SUB
